# _*_ coding: utf-8 _*_
#!/usr/bin/env python

#      ___________________
#  ___| Modulbeschreibung \_________________________________________________________________________
# | Der Client ist für die Verbindung der Spiellogik mit den anderen Spielern verantwortlich
# |__________________________________________________________________| Zuständigkeit [Jannik |____


import socket
import threading
import thread
import cPickle
import sys
import random
import time

VERSION = "0.0001"

##Eventuell in einen Thread auslagern?
class Client(threading.Thread):
	
	def __init__(self, race , server = "192.168.178.20", port = 50000 ):
		
		threading.Thread.__init__(self)
		#self.stoped	= threading.Event()
		self.race = race
		self.connection = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
		
		try:
			self.connection.connect ( ( server, port ) )
		except:
			pass
		
		self.playerinf = ["Verbindungsaufbau","..."]
		self.playernumber = None
		self.startRace = False
		self.connection_successfull = False
		self.positions = [None,None,None,None,None,None,None,None] #Platzierungen in der Reihenfolge 1,2,3...
		self.run_thread = True
		
	def run(self, name = "Anonymous"):
		#while not self.stoped.isSet():
		
		#Verbindungsdaten z.B. Name senden
		data = {"name":name}
		

		buf = cPickle.dumps(data)
		
		try:
			self.connection.send(buf)
		except socket.error, (value, message):
			self._disconnect()
			raise socket.error(value, message)
		
		#Verbindungsdaten empfangen
		try:
			buf = self.connection.recv(1024)
		except socket.error, (value, message):
			self._disconnect()
			raise socket.error(value, message)

		try:
			data = cPickle.loads(buf)
		except cPickle.cPickleError, (args, message):
			raise cPickle.cPickleError(args, message)
		
		if data.has_key("race"):
			self.connection_successfull = False
		else: self.connection_successfull = True
		
		#Wenn die Verbindung erfolgreich ist so wird dem Spieler eine Nummer zugewiesen und die Empfangenschleife betreten
		
		if self.connection_successfull:
			self.playernumber = data["number"]
			self.playerinf = data["playerinf"]
			
			
			while self.run_thread:
				
				
				#Daten empfangen
				try:
					buf = self.connection.recv(4096)
					buf2 = buf.split("#")
				except socket.error, (value, message):
					break
					raise socket.error(value, message)
	
				for i in buf2:
					if i != '':
						try:	
							data = cPickle.loads(i)
						except cPickle.cPickleError, (args, message):
							raise cPickle.cPickleError(args, message)
						###Daten Bearbeiten und Einfuegen!
						
						#Updatet den Status des Rennens (Beendet, Gestartet, Wartend etc.)
						if data.has_key("race"):
							if data["race"] == "start":
								self.startRace = True
							
							elif data["race"] == "finish":
								##Gewinnerliste erstellen!
								for i in range(8):
									pos = False
									if self.positions[i] == None and pos == False:
										self.positions[i] = data["number"]
										pos = True
						
						self.race.lock.acquire()
						#Updatet die Spielerinformationen		
						if data.has_key("playerinf"):
							self.playerinf = data["playerinf"]
						
						#Tastendruecke werden aktualisiert 
						if data.has_key("key_up"):
							self.race.game_logic.keys_pressed[int(data["number"])][0] = data["key_up"]
						
						if data.has_key("key_down"):
							self.race.game_logic.keys_pressed[int(data["number"])][1] = data["key_down"]
		
						if data.has_key("key_left"):
							self.race.game_logic.keys_pressed[int(data["number"])][2] = data["key_left"]
		
						if data.has_key("key_right"):
							self.race.game_logic.keys_pressed[int(data["number"])][3] = data["key_right"]
		
						#Synchronisation der Daten
						if data.has_key("x_pos"):
							#Die Positionsdaten werden aktualisiert
							try:
								kartnumber = int(data["number"])
								self.race.players[kartnumber].x_pos 	= data["x_pos"]
								self.race.players[kartnumber].y_pos		= data["y_pos"]
								self.race.players[kartnumber].x_speed	= data["x_speed"]
								self.race.players[kartnumber].y_speed	= data["x_speed"]
								self.race.players[kartnumber].angle		= data["angle"]
								self.race.players[kartnumber].item		= data["item"]#
							except:
								pass
						self.race.lock.release()
						
	def syncData(self):
		'''Synchronisiert alle Daten'''
		
		self.playerdata = {	
				"number"	: self.playernumber,	#Nummer des Spielers
				
				#Daten, je nach Art der Daten unterschiedlich, hier Positionsdaten
				"x_pos"		: self.race.players[int(self.playernumber)].x_pos ,
				"y_pos"		: self.race.players[int(self.playernumber)].y_pos,
				"x_speed" 	: self.race.players[int(self.playernumber)].x_speed,
				"y_speed"	: self.race.players[int(self.playernumber)].y_speed,
				"angle"		: self.race.players[int(self.playernumber)].angle,
				"item"		: self.race.players[int(self.playernumber)].item,}
		
		#Daten senden
		buf = "#" + cPickle.dumps(self.playerdata)
		try:
			self.connection.send(buf)
			
		except socket.error, (value, message):
			return False
			self.connection.close()
		return True
	
	def sendKeys(self, keys):
		'''Synchonisiert nur die Tastendruecke'''
		
		self.playerdata = keys
		
		buf = "#" + cPickle.dumps(self.playerdata)
		try:
			self.connection.send(buf)
			
		except socket.error, (value, message):
			return False
			self.connection.close()
		return True

	def sendFinish(self):
		'''Wird aufgerufen wenn die Ziellinie durchfahren wird'''
		self.playerdata = {	
		"number"	: self.playernumber,	#Nummer des Spielers
		"race"		: "finish"}

		
		#Daten senden
		buf = "#" + cPickle.dumps(self.playerdata)
		try:
			self.connection.send(buf)
			
		except socket.error, (value, message):
			return False
			self.connection.close()
		return True
		
	def _disconnect(self):
		'''Beendet die Verbindung'''
		self.connection.close()
	
	def getPlayerInf(self):
		'''Liefert die Spielerdaten'''
		return self.playerinf

	def getRaceState(self):
		'''Liefert zurück ob das Rennen gestartet wurde'''
		if self.startRace:
			return "start"
		else: return None
		
	def conSucessfull(self):
		'''Liefert zurück, ob die Verbindung zum Server erfolgreich war'''
		return self.connection_successfull
	
	def stopClient(self):
		self.run_thread = False

if __name__ == '__main__':
	client = Client(None)
	#network.run()
	#Empfaengt aktualisierte Daten vom Server und gleicht sie mit den lokalen ab
	thread.start_new_thread(client.run,() )
	while True:
		time.sleep(1)
		#Aufrufen um die eigenen Daten ueber das Netzwerk zu verschicken
		#thread.start_new_thread(network.updateData,() )
		

